package com.example.demo.service.shop;

import com.example.demo.entity.Order;
import com.example.demo.entity.Product;
import com.example.demo.entity.TradeRecord;
import com.example.demo.entity.member.User;
import com.example.demo.module.mq.CancelOrderSender;
import com.example.demo.module.mq.CreateOrderSender;
import com.example.demo.repository.OrderRepository;
import com.example.demo.repository.TradeRecordRepository;
import com.example.demo.service.SeckillService;
import com.example.demo.service.member.UserSecurityService;
import com.example.demo.util.RandomUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;

/**
 * Copyright (C), 2019-2019, XXX有限公司
 * FileName: OrderServiceImpl
 * Author:   longzhonghua
 * Date:     2019/4/15 10:51
 *
 * @Description: $description$
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
@Service
public class OrderServiceImpl implements OrderService {
    @Resource
    private OrderRepository orderRepository;
    @Autowired
    private CancelOrderSender cancelOrderSender;
    @Resource
    private CreateOrderSender createOrderSender;
    @Resource
    private TradeRecordRepository tradeRecordRepository;
    @Resource
    private UserSecurityService userSecurityService;
    @Resource
    private ProductService productService;
    @Resource
    private SeckillService seckillService;

    @Override
    public Order findById(Long order_id) {
        return orderRepository.findByid(order_id);
    }

    /**
     *
     * @param order_no
     * @return 状态等于2表示已付款，1已取消，0待支付
     */
    @Override
    public boolean processed(String order_no) {
        Order order = orderRepository.findByOrderNo(order_no);
        return order.getStatus()==2&&order.getTrade_no()!=null;
    }

    /**
     * 此方法处理第三方支付成功后回调通知的业务，
     * 后台mq可能会同一时间取消该订单
     * @param order_no
     * @param transactionId
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void paySuccess(String order_no,String transactionId) {
        TradeRecord record = new TradeRecord();
        record.setOrderNo(order_no);
        record.setTradeNo(transactionId);
        record.setStatus(0);//未处理
        try{
            tradeRecordRepository.save(record);
            //无异常，则更新订单状态为已支付
            Order order = orderRepository.findByOrderNo(order_no);
            order.setStatus(2);//已支付
            order.setTrade_no(transactionId);
            //通过version实现乐观锁，防止mq或用户取消订单,mybatis可以检查返回值是否等于1
            orderRepository.save(order);//jpa更新
            //修改库存，实际项目可以异步通知库存，
            // 防止库存系统异常，影响订单支付
            productService.updateStock(order.getProduct_id(),order.getCount());
            //修改积分
            //通知仓库准备发货
        }  catch (Exception e) {
            //必须进行异常处理，记录失败的订单到数据库，人工或自动处理
            e.printStackTrace();
        }
    }

    @Override
    public Order findByOrderNo(String orderNo) {
        return orderRepository.findByOrderNo(orderNo);
    }

    /**
     * 创建秒杀订单
     * 1、发送订单创建消息到mq，减轻数据库并发压力
     * @param
     */
    @Override
    public boolean createSeckillOrder(Long userId, Long productId) {
        //保存订单
        Product product = productService.findByid(productId);
        Order order = new Order();
        order.setStatus(0);//未支付状态
        order.setUserId(userId);
        order.setProduct_id(product.getId());
        order.setCount(1);
        //价格信息要从库中获取,不然黑客伪造订单,购买虚拟产品就会自动发货
        order.setAmount(product.getSeckill_price());//秒杀价格
        //订单编号
        order.setOrderNo(generateOrderNo());
        //发送订单创建消息
        System.out.println("发送创建订单消息:"+order.getOrderNo());
        createOrderSender.sendOrder("create_order_queue",order);
        return true;
    }

    /**
     * 创建普通订单
     * 1、保存订单到数据库
     * 2、发送延迟取消订单消息到mq
     * @param order
     */
    @Override
    public void createOrder(Order order) {
        if(StringUtils.isEmpty(order.getOrderNo())) {//秒杀订单已经有编号
            order.setOrderNo(generateOrderNo());
        }
        orderRepository.save(order);
        //发送取消延迟取消订单消息
        cancelOrderSender.sendMsg("delay_queue_1", order.getOrderNo());
    }

    /**
     * 取消订单第二版本，手动执行update
     * @param orderNo
     */
    @Override
    public boolean expireOrder(String orderNo) {
        return orderRepository.expireOrder(orderNo) == 1;
    }
    /**
     * 取消订单第一个版本，通过JPA乐观锁
     * @param orderNo
     */
    @Override
    public void cancelOrder(String orderNo) {
        Order order = orderRepository.findByOrderNo(orderNo);
        if(order!=null && order.getStatus()==0) {//未支付
            try{
                order.setStatus(1);//设置订单状态为已取消
                //通过version实现乐观锁，防止mq和用户同时操作订单,mybatis可以加version并检查返回值是否等于1
                //update order set status=1,version=version+1
                // where id=:id and version=3
                orderRepository.save(order);//更新订单状态
            } catch (Exception e) {
                e.printStackTrace();
                System.err.println("mq未成功取消订单,id:" + order.getId()
                        +",orderNo:" + order.getOrderNo() +
                        "，记录到失败日志，手动处理，待实现："+e.getClass());
            }

        } else {
            //异常订单处理
        }
    }

    @Override
    public Page<Order> findByAccount(String accountName, Integer page, Integer size) {
        User user = (User) userSecurityService.loadUserByUsername(accountName);
        Order order = new Order();
        order.setUserId(user.getId());
        if(page==null)page=0;
        if(size==null)size=5;
        return orderRepository.findAll(Example.of(order),
                PageRequest.of(page,size, Sort.Direction.DESC,"createTime"));
//        return orderRepository.findByUserId(user.getId());
    }

    /**
     * 模拟生成订单编号,需根据业务完善
     * @return
     */
    private static String generateOrderNo() {
        return System.currentTimeMillis() + "_" + RandomUtil.randomInteger(6);
    }
}
